﻿using System.Diagnostics.Contracts;

namespace System.Diagnostics
{
	/// <summary>
	/// Provides trace extension methods for <see cref="TraceSource"/>.
	/// </summary>
	public static class TraceSourceExtensions
	{
#if !SILVERLIGHT && !NETFX_CORE
		private static readonly object gate = Type
			.GetType("System.Diagnostics.TraceInternal, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", throwOnError: true)
			.GetField("critSec", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
#else
		internal static object Gate
		{
			get
			{
				return gate;
			}
		}

		private static readonly object gate = new object();
#endif
		private const int eventId = 0;

		/// <summary>
		/// Sends the specified message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void Trace(this TraceSource source, string format, params object[] args)
		{
			Contract.Requires(source != null);

			Trace(source, DaveSexton.Labs.LabTraceSource.Format(format, args));
		}

		/// <summary>
		/// Sends the specified message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="message">The message to be sent.</param>
		public static void Trace(this TraceSource source, string message)
		{
			Contract.Requires(source != null);

			message = message ?? string.Empty;

			var listeners = source.Listeners;

#if !SILVERLIGHT
			Contract.Assume(listeners != null);
#endif

			lock (gate)
			{
				for (int i = 0; i < listeners.Count; i++)
				{
					var listener = listeners[i];

#if SILVERLIGHT
					Contract.Assume(listener != null);
#endif

					listener.Write(message);
				}
			}
		}

		/// <summary>
		/// Sends the specified <paramref name="value"/> to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the value.</param>
		/// <param name="value">The object to be sent.</param>
		public static void Trace(this TraceSource source, object value)
		{
			Contract.Requires(source != null);

			Trace(source, value == null ? string.Empty : value.ToString());
		}

		/// <summary>
		/// Sends the specified message to all listeners and starts a new line.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void TraceLine(this TraceSource source, string format, params object[] args)
		{
			Contract.Requires(source != null);

			TraceLine(source, DaveSexton.Labs.LabTraceSource.Format(format, args));
		}

		/// <summary>
		/// Sends the specified message to all listeners and starts a new line.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="message">The message to be sent.</param>
		public static void TraceLine(this TraceSource source, string message)
		{
			Contract.Requires(source != null);

			message = message ?? string.Empty;

			var listeners = source.Listeners;

#if !SILVERLIGHT
			Contract.Assume(listeners != null);
#endif

			lock (gate)
			{
				for (int i = 0; i < listeners.Count; i++)
				{
					var listener = listeners[i];

#if SILVERLIGHT
					Contract.Assume(listener != null);
#endif

					listener.WriteLine(message);
				}
			}
		}

		/// <summary>
		/// Sends the specified <paramref name="value"/> to all listeners and starts a new line.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the value.</param>
		/// <param name="value">The object to be sent.</param>
		public static void TraceLine(this TraceSource source, object value)
		{
			Contract.Requires(source != null);

			TraceLine(source, value == null ? string.Empty : value.ToString());
		}

		/// <summary>
		/// Sends the specified event message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="eventType">The type of the event.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void TraceEvent(this TraceSource source, TraceEventType eventType, string format, params object[] args)
		{
			Contract.Requires(source != null);

			source.TraceEvent(eventType, eventId, format ?? string.Empty, args);
		}

		/// <summary>
		/// Sends the specified event message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="eventType">The type of the event.</param>
		/// <param name="message">The message to be sent.</param>
		public static void TraceEvent(this TraceSource source, TraceEventType eventType, string message)
		{
			Contract.Requires(source != null);

			source.TraceEvent(eventType, eventId, message ?? string.Empty);
		}

		/// <summary>
		/// Sends the specified <paramref name="exception"/> to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the <paramref name="exception"/>.</param>
		/// <param name="exception">The <see cref="Exception"/> to be sent.</param>
		public static void TraceError(this TraceSource source, Exception exception)
		{
			Contract.Requires(source != null);

			source.TraceEvent(TraceEventType.Error, eventId, (exception == null) ? string.Empty : exception.ToString());
		}

#if !SILVERLIGHT && !NETFX_CORE
		/// <summary>
		/// When error tracing is enabled, invokes the specified <paramref name="messageFactory"/> function and traces the result.
		/// </summary>
		/// <remarks>
		/// This overload is useful for when it's expensive to create trace messages.  By passing in a function instead, 
		/// the configured trace level may be consulted first to see if it allows messages to be written at the specified 
		/// level.  Only if the mesage can be written will the function be invoked.
		/// </remarks>
		public static void TraceError(this TraceSource source, Func<string> messageFactory)
		{
			Contract.Requires(source != null);
			Contract.Requires(messageFactory != null);

			var sourceSwitch = source.Switch;

			if (sourceSwitch.ShouldTrace(TraceEventType.Error))
			{
				source.TraceEvent(TraceEventType.Error, eventId, messageFactory() ?? string.Empty);
			}
		}
#endif

		/// <summary>
		/// Sends the specified error message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="message">The message to be sent.</param>
		public static void TraceError(this TraceSource source, string message)
		{
			Contract.Requires(source != null);

			source.TraceEvent(TraceEventType.Error, eventId, message ?? string.Empty);
		}

		/// <summary>
		/// Sends the specified error message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void TraceError(this TraceSource source, string format, params object[] args)
		{
			Contract.Requires(source != null);

			source.TraceEvent(TraceEventType.Error, eventId, format ?? string.Empty, args);
		}

#if !SILVERLIGHT && !NETFX_CORE
		/// <summary>
		/// When warning tracing is enabled, invokes the specified <paramref name="messageFactory"/> function and traces the result.
		/// </summary>
		/// <remarks>
		/// This overload is useful for when it's expensive to create trace messages.  By passing in a function instead, 
		/// the configured trace level may be consulted first to see if it allows messages to be written at the specified 
		/// level.  Only if the mesage can be written will the function be invoked.
		/// </remarks>
		public static void TraceWarning(this TraceSource source, Func<string> messageFactory)
		{
			Contract.Requires(source != null);
			Contract.Requires(messageFactory != null);

			var sourceSwitch = source.Switch;

			if (sourceSwitch.ShouldTrace(TraceEventType.Warning))
			{
				source.TraceEvent(TraceEventType.Warning, eventId, messageFactory() ?? string.Empty);
			}
		}
#endif

		/// <summary>
		/// Sends the specified warning message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="message">The message to be sent.</param>
		public static void TraceWarning(this TraceSource source, string message)
		{
			Contract.Requires(source != null);

			source.TraceEvent(TraceEventType.Warning, eventId, message ?? string.Empty);
		}

		/// <summary>
		/// Sends the specified warning message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void TraceWarning(this TraceSource source, string format, params object[] args)
		{
			Contract.Requires(source != null);

			source.TraceEvent(TraceEventType.Warning, eventId, format ?? string.Empty, args);
		}

#if !SILVERLIGHT && !NETFX_CORE
		/// <summary>
		/// When warning tracing is enabled, invokes the specified <paramref name="predicate"/> function and if <see langword="true"/>, 
		/// invokes the specified <paramref name="messageFactory"/> function and traces the result.
		/// </summary>
		/// <remarks>
		/// This overload is useful for when it's expensive to create trace messages.  By passing in a function instead, 
		/// the configured trace level may be consulted first to see if it allows messages to be written at the specified 
		/// level.  Only if the mesage can be written will the function be invoked.
		/// </remarks>
		public static void TraceWarningIf(this TraceSource source, Func<bool> predicate, Func<string> messageFactory)
		{
			Contract.Requires(source != null);
			Contract.Requires(predicate != null);
			Contract.Requires(messageFactory != null);

			var sourceSwitch = source.Switch;

			if (sourceSwitch.ShouldTrace(TraceEventType.Warning) && predicate())
			{
				source.TraceEvent(TraceEventType.Warning, eventId, messageFactory() ?? string.Empty);
			}
		}
#endif

		/// <summary>
		/// Sends the specified warning message to all listeners if the specified <paramref name="predicate"/> is <see langword="true"/>.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="predicate">A value indicating whether the message is sent.</param>
		/// <param name="message">The message to be sent.</param>
		public static void TraceWarningIf(this TraceSource source, bool predicate, string message)
		{
			Contract.Requires(source != null);

			if (predicate)
			{
				source.TraceEvent(TraceEventType.Warning, eventId, message);
			}
		}

		/// <summary>
		/// Sends the specified warning message to all listeners if the specified <paramref name="predicate"/> is <see langword="true"/>.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="predicate">A value indicating whether the message is sent.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void TraceWarningIf(this TraceSource source, bool predicate, string format, params object[] args)
		{
			Contract.Requires(source != null);

			if (predicate)
			{
				source.TraceEvent(TraceEventType.Warning, eventId, format ?? string.Empty, args);
			}
		}

#if !SILVERLIGHT && !NETFX_CORE
		/// <summary>
		/// When verbose tracing is enabled, invokes the specified <paramref name="messageFactory"/> function and traces the result.
		/// </summary>
		/// <remarks>
		/// This overload is useful for when it's expensive to create trace messages.  By passing in a function instead, 
		/// the configured trace level may be consulted first to see if it allows messages to be written at the specified 
		/// level.  Only if the mesage can be written will the function be invoked.
		/// </remarks>
		public static void TraceVerbose(this TraceSource source, Func<string> messageFactory)
		{
			Contract.Requires(source != null);
			Contract.Requires(messageFactory != null);

			var sourceSwitch = source.Switch;

			if (sourceSwitch.ShouldTrace(TraceEventType.Verbose))
			{
				source.TraceEvent(TraceEventType.Verbose, eventId, messageFactory() ?? string.Empty);
			}
		}
#endif

		/// <summary>
		/// Sends the specified verbose message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="message">The message to be sent.</param>
		public static void TraceVerbose(this TraceSource source, string message)
		{
			Contract.Requires(source != null);

			source.TraceEvent(TraceEventType.Verbose, eventId, message ?? string.Empty);
		}

		/// <summary>
		/// Sends the specified verbose message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void TraceVerbose(this TraceSource source, string format, params object[] args)
		{
			Contract.Requires(source != null);

			source.TraceEvent(TraceEventType.Verbose, eventId, format ?? string.Empty, args);
		}

#if !SILVERLIGHT && !NETFX_CORE
		/// <summary>
		/// When verbose tracing is enabled, invokes the specified <paramref name="predicate"/> function and if <see langword="true"/>, 
		/// invokes the specified <paramref name="messageFactory"/> function and traces the result.
		/// </summary>
		/// <remarks>
		/// This overload is useful for when it's expensive to create trace messages.  By passing in a function instead, 
		/// the configured trace level may be consulted first to see if it allows messages to be written at the specified 
		/// level.  Only if the mesage can be written will the function be invoked.
		/// </remarks>
		public static void TraceVerboseIf(this TraceSource source, Func<bool> predicate, Func<string> messageFactory)
		{
			Contract.Requires(source != null);
			Contract.Requires(predicate != null);
			Contract.Requires(messageFactory != null);

			var sourceSwitch = source.Switch;

			if (sourceSwitch.ShouldTrace(TraceEventType.Verbose) && predicate())
			{
				source.TraceEvent(TraceEventType.Verbose, eventId, messageFactory() ?? string.Empty);
			}
		}
#endif

		/// <summary>
		/// Sends the specified verbose message to all listeners if the specified <paramref name="predicate"/> is <see langword="true"/>.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="predicate">A value indicating whether the message is sent.</param>
		/// <param name="message">The message to be sent.</param>
		public static void TraceVerboseIf(this TraceSource source, bool predicate, string message)
		{
			Contract.Requires(source != null);

			if (predicate)
			{
				source.TraceEvent(TraceEventType.Verbose, eventId, message ?? string.Empty);
			}
		}

		/// <summary>
		/// Sends the specified verbose message to all listeners if the specified <paramref name="predicate"/> is <see langword="true"/>.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="predicate">A value indicating whether the message is sent.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void TraceVerboseIf(this TraceSource source, bool predicate, string format, params object[] args)
		{
			Contract.Requires(source != null);

			if (predicate)
			{
				source.TraceEvent(TraceEventType.Verbose, eventId, format ?? string.Empty, args);
			}
		}

#if !SILVERLIGHT && !NETFX_CORE
		/// <summary>
		/// When information tracing is enabled, invokes the specified <paramref name="messageFactory"/> function and traces the result.
		/// </summary>
		/// <remarks>
		/// This overload is useful for when it's expensive to create trace messages.  By passing in a function instead, 
		/// the configured trace level may be consulted first to see if it allows messages to be written at the specified 
		/// level.  Only if the mesage can be written will the function be invoked.
		/// </remarks>
		public static void TraceInformation(this TraceSource source, Func<string> messageFactory)
		{
			Contract.Requires(source != null);
			Contract.Requires(messageFactory != null);

			var sourceSwitch = source.Switch;

			if (sourceSwitch.ShouldTrace(TraceEventType.Information))
			{
				source.TraceInformation(messageFactory() ?? string.Empty);
			}
		}

		/// <summary>
		/// When information tracing is enabled, invokes the specified <paramref name="messageFactory"/> function and traces the result.
		/// </summary>
		/// <remarks>
		/// This overload is useful for when it's expensive to create trace messages.  By passing in a function instead, 
		/// the configured trace level may be consulted first to see if it allows messages to be written at the specified 
		/// level.  Only if the mesage can be written will the function be invoked.
		/// </remarks>
		public static void TraceInformationIf(this TraceSource source, Func<string> messageFactory)
		{
			Contract.Requires(source != null);
			Contract.Requires(messageFactory != null);

			var sourceSwitch = source.Switch;

			if (sourceSwitch.ShouldTrace(TraceEventType.Information))
			{
				source.TraceInformation(messageFactory() ?? string.Empty);
			}
		}

		/// <summary>
		/// When information tracing is enabled, invokes the specified <paramref name="predicate"/> function and if <see langword="true"/>, 
		/// invokes the specified <paramref name="messageFactory"/> function and traces the result.
		/// </summary>
		/// <remarks>
		/// This overload is useful for when it's expensive to create trace messages.  By passing in a function instead, 
		/// the configured trace level may be consulted first to see if it allows messages to be written at the specified 
		/// level.  Only if the mesage can be written will the function be invoked.
		/// </remarks>
		public static void TraceInformationIf(this TraceSource source, Func<bool> predicate, Func<string> messageFactory)
		{
			Contract.Requires(source != null);
			Contract.Requires(predicate != null);
			Contract.Requires(messageFactory != null);

			var sourceSwitch = source.Switch;

			if (sourceSwitch.ShouldTrace(TraceEventType.Information) && predicate())
			{
				source.TraceInformation(messageFactory() ?? string.Empty);
			}
		}
#endif

		/// <summary>
		/// Sends the specified informational message to all listeners if the specified <paramref name="predicate"/> is <see langword="true"/>.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="predicate">A value indicating whether the message is sent.</param>
		/// <param name="message">The message to be sent.</param>
		public static void TraceInformationIf(this TraceSource source, bool predicate, string message)
		{
			Contract.Requires(source != null);

			if (predicate)
			{
				source.TraceInformation(message ?? string.Empty);
			}
		}

		/// <summary>
		/// Sends the specified informational message to all listeners if the specified <paramref name="predicate"/> is <see langword="true"/>.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="predicate">A value indicating whether the message is sent.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void TraceInformationIf(this TraceSource source, bool predicate, string format, params object[] args)
		{
			Contract.Requires(source != null);

			if (predicate)
			{
				source.TraceInformation(format ?? string.Empty, args);
			}
		}

#if !SILVERLIGHT && !NETFX_CORE
		/// <summary>
		/// When activity tracing is enabled, invokes the specified <paramref name="messageFactory"/> function and traces the result.
		/// </summary>
		/// <remarks>
		/// This overload is useful for when it's expensive to create trace messages.  By passing in a function instead, 
		/// the configured trace level may be consulted first to see if it allows messages to be written at the specified 
		/// level.  Only if the mesage can be written will the function be invoked.
		/// </remarks>
		public static void TraceStart(this TraceSource source, Func<string> messageFactory)
		{
			Contract.Requires(source != null);
			Contract.Requires(messageFactory != null);

			var sourceSwitch = source.Switch;

			if (sourceSwitch.ShouldTrace(TraceEventType.Start))
			{
				source.TraceEvent(TraceEventType.Start, eventId, messageFactory() ?? string.Empty);
			}
		}
#endif

		/// <summary>
		/// Sends the specified start message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="message">The message to be sent.</param>
		public static void TraceStart(this TraceSource source, string message)
		{
			Contract.Requires(source != null);

			source.TraceEvent(TraceEventType.Start, eventId, message ?? string.Empty);
		}

		/// <summary>
		/// Sends the specified start message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void TraceStart(this TraceSource source, string format, params object[] args)
		{
			Contract.Requires(source != null);

			source.TraceEvent(TraceEventType.Start, eventId, format ?? string.Empty, args);
		}

#if !SILVERLIGHT && !NETFX_CORE
		/// <summary>
		/// When activity tracing is enabled, invokes the specified <paramref name="predicate"/> function and if <see langword="true"/>, 
		/// invokes the specified <paramref name="messageFactory"/> function and traces the result.
		/// </summary>
		/// <remarks>
		/// This overload is useful for when it's expensive to create trace messages.  By passing in a function instead, 
		/// the configured trace level may be consulted first to see if it allows messages to be written at the specified 
		/// level.  Only if the mesage can be written will the function be invoked.
		/// </remarks>
		public static void TraceStartIf(this TraceSource source, Func<bool> predicate, Func<string> messageFactory)
		{
			Contract.Requires(source != null);
			Contract.Requires(predicate != null);
			Contract.Requires(messageFactory != null);

			var sourceSwitch = source.Switch;

			if (sourceSwitch.ShouldTrace(TraceEventType.Start) && predicate())
			{
				source.TraceEvent(TraceEventType.Start, eventId, messageFactory() ?? string.Empty);
			}
		}
#endif

		/// <summary>
		/// Sends the specified start message to all listeners if the specified <paramref name="predicate"/> is <see langword="true"/>.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="predicate">A value indicating whether the message is sent.</param>
		/// <param name="message">The message to be sent.</param>
		public static void TraceStartIf(this TraceSource source, bool predicate, string message)
		{
			Contract.Requires(source != null);

			if (predicate)
			{
				source.TraceEvent(TraceEventType.Start, eventId, message ?? string.Empty);
			}
		}

		/// <summary>
		/// Sends the specified start message to all listeners if the specified <paramref name="predicate"/> is <see langword="true"/>.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="predicate">A value indicating whether the message is sent.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void TraceStartIf(this TraceSource source, bool predicate, string format, params object[] args)
		{
			Contract.Requires(source != null);

			if (predicate)
			{
				source.TraceEvent(TraceEventType.Start, eventId, format ?? string.Empty, args);
			}
		}

#if !SILVERLIGHT && !NETFX_CORE
		/// <summary>
		/// When activity tracing is enabled, invokes the specified <paramref name="messageFactory"/> function and traces the result.
		/// </summary>
		/// <remarks>
		/// This overload is useful for when it's expensive to create trace messages.  By passing in a function instead, 
		/// the configured trace level may be consulted first to see if it allows messages to be written at the specified 
		/// level.  Only if the mesage can be written will the function be invoked.
		/// </remarks>
		public static void TraceStop(this TraceSource source, Func<string> messageFactory)
		{
			Contract.Requires(source != null);
			Contract.Requires(messageFactory != null);

			var sourceSwitch = source.Switch;

			if (sourceSwitch.ShouldTrace(TraceEventType.Stop))
			{
				source.TraceEvent(TraceEventType.Stop, eventId, messageFactory() ?? string.Empty);
			}
		}
#endif

		/// <summary>
		/// Sends the specified stop message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="message">The message to be sent.</param>
		public static void TraceStop(this TraceSource source, string message)
		{
			Contract.Requires(source != null);

			source.TraceEvent(TraceEventType.Stop, eventId, message ?? string.Empty);
		}

		/// <summary>
		/// Sends the specified stop message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void TraceStop(this TraceSource source, string format, params object[] args)
		{
			Contract.Requires(source != null);

			source.TraceEvent(TraceEventType.Stop, eventId, format ?? string.Empty, args);
		}

#if !SILVERLIGHT && !NETFX_CORE
		/// <summary>
		/// When activity tracing is enabled, invokes the specified <paramref name="predicate"/> function and if <see langword="true"/>, 
		/// invokes the specified <paramref name="messageFactory"/> function and traces the result.
		/// </summary>
		/// <remarks>
		/// This overload is useful for when it's expensive to create trace messages.  By passing in a function instead, 
		/// the configured trace level may be consulted first to see if it allows messages to be written at the specified 
		/// level.  Only if the mesage can be written will the function be invoked.
		/// </remarks>
		public static void TraceStopIf(this TraceSource source, Func<bool> predicate, Func<string> messageFactory)
		{
			Contract.Requires(source != null);
			Contract.Requires(predicate != null);
			Contract.Requires(messageFactory != null);

			var sourceSwitch = source.Switch;

			if (sourceSwitch.ShouldTrace(TraceEventType.Stop) && predicate())
			{
				source.TraceEvent(TraceEventType.Stop, eventId, messageFactory() ?? string.Empty);
			}
		}
#endif

		/// <summary>
		/// Sends the specified stop message to all listeners if the specified <paramref name="predicate"/> is <see langword="true"/>.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="predicate">A value indicating whether the message is sent.</param>
		/// <param name="message">The message to be sent.</param>
		public static void TraceStopIf(this TraceSource source, bool predicate, string message)
		{
			Contract.Requires(source != null);

			if (predicate)
			{
				source.TraceEvent(TraceEventType.Stop, eventId, message ?? string.Empty);
			}
		}

		/// <summary>
		/// Sends the specified stop message to all listeners if the specified <paramref name="predicate"/> is <see langword="true"/>.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="predicate">A value indicating whether the message is sent.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void TraceStopIf(this TraceSource source, bool predicate, string format, params object[] args)
		{
			Contract.Requires(source != null);

			if (predicate)
			{
				source.TraceEvent(TraceEventType.Stop, eventId, format ?? string.Empty, args);
			}
		}

#if !SILVERLIGHT && !NETFX_CORE
		/// <summary>
		/// When activity tracing is enabled, invokes the specified <paramref name="messageFactory"/> function and traces the result.
		/// </summary>
		/// <remarks>
		/// This overload is useful for when it's expensive to create trace messages.  By passing in a function instead, 
		/// the configured trace level may be consulted first to see if it allows messages to be written at the specified 
		/// level.  Only if the mesage can be written will the function be invoked.
		/// </remarks>
		public static void TraceResume(this TraceSource source, Func<string> messageFactory)
		{
			Contract.Requires(source != null);
			Contract.Requires(messageFactory != null);

			var sourceSwitch = source.Switch;

			if (sourceSwitch.ShouldTrace(TraceEventType.Resume))
			{
				source.TraceEvent(TraceEventType.Resume, eventId, messageFactory() ?? string.Empty);
			}
		}
#endif

		/// <summary>
		/// Sends the specified resume message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="message">The message to be sent.</param>
		public static void TraceResume(this TraceSource source, string message)
		{
			Contract.Requires(source != null);

			source.TraceEvent(TraceEventType.Resume, eventId, message ?? string.Empty);
		}

		/// <summary>
		/// Sends the specified resume message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void TraceResume(this TraceSource source, string format, params object[] args)
		{
			Contract.Requires(source != null);

			source.TraceEvent(TraceEventType.Resume, eventId, format ?? string.Empty, args);
		}

#if !SILVERLIGHT && !NETFX_CORE
		/// <summary>
		/// When activity tracing is enabled, invokes the specified <paramref name="predicate"/> function and if <see langword="true"/>, 
		/// invokes the specified <paramref name="messageFactory"/> function and traces the result.
		/// </summary>
		/// <remarks>
		/// This overload is useful for when it's expensive to create trace messages.  By passing in a function instead, 
		/// the configured trace level may be consulted first to see if it allows messages to be written at the specified 
		/// level.  Only if the mesage can be written will the function be invoked.
		/// </remarks>
		public static void TraceResumeIf(this TraceSource source, Func<bool> predicate, Func<string> messageFactory)
		{
			Contract.Requires(source != null);
			Contract.Requires(predicate != null);
			Contract.Requires(messageFactory != null);

			var sourceSwitch = source.Switch;

			if (sourceSwitch.ShouldTrace(TraceEventType.Resume) && predicate())
			{
				source.TraceEvent(TraceEventType.Resume, eventId, messageFactory() ?? string.Empty);
			}
		}
#endif

		/// <summary>
		/// Sends the specified resume message to all listeners if the specified <paramref name="predicate"/> is <see langword="true"/>.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="predicate">A value indicating whether the message is sent.</param>
		/// <param name="message">The message to be sent.</param>
		public static void TraceResumeIf(this TraceSource source, bool predicate, string message)
		{
			Contract.Requires(source != null);

			if (predicate)
			{
				source.TraceEvent(TraceEventType.Resume, eventId, message ?? string.Empty);
			}
		}

		/// <summary>
		/// Sends the specified resume message to all listeners if the specified <paramref name="predicate"/> is <see langword="true"/>.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="predicate">A value indicating whether the message is sent.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void TraceResumeIf(this TraceSource source, bool predicate, string format, params object[] args)
		{
			Contract.Requires(source != null);

			if (predicate)
			{
				source.TraceEvent(TraceEventType.Resume, eventId, format ?? string.Empty, args);
			}
		}

#if !SILVERLIGHT && !NETFX_CORE
		/// <summary>
		/// When activity tracing is enabled, invokes the specified <paramref name="messageFactory"/> function and traces the result.
		/// </summary>
		/// <remarks>
		/// This overload is useful for when it's expensive to create trace messages.  By passing in a function instead, 
		/// the configured trace level may be consulted first to see if it allows messages to be written at the specified 
		/// level.  Only if the mesage can be written will the function be invoked.
		/// </remarks>
		public static void TraceSuspend(this TraceSource source, Func<string> messageFactory)
		{
			Contract.Requires(source != null);
			Contract.Requires(messageFactory != null);

			var sourceSwitch = source.Switch;

			if (sourceSwitch.ShouldTrace(TraceEventType.Suspend))
			{
				source.TraceEvent(TraceEventType.Suspend, eventId, messageFactory() ?? string.Empty);
			}
		}
#endif

		/// <summary>
		/// Sends the specified suspend message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="message">The message to be sent.</param>
		public static void TraceSuspend(this TraceSource source, string message)
		{
			Contract.Requires(source != null);

			source.TraceEvent(TraceEventType.Suspend, eventId, message ?? string.Empty);
		}

		/// <summary>
		/// Sends the specified suspend message to all listeners.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void TraceSuspend(this TraceSource source, string format, params object[] args)
		{
			Contract.Requires(source != null);

			source.TraceEvent(TraceEventType.Suspend, eventId, format ?? string.Empty, args);
		}

#if !SILVERLIGHT && !NETFX_CORE
		/// <summary>
		/// When activity tracing is enabled, invokes the specified <paramref name="predicate"/> function and if <see langword="true"/>, 
		/// invokes the specified <paramref name="messageFactory"/> function and traces the result.
		/// </summary>
		/// <remarks>
		/// This overload is useful for when it's expensive to create trace messages.  By passing in a function instead, 
		/// the configured trace level may be consulted first to see if it allows messages to be written at the specified 
		/// level.  Only if the mesage can be written will the function be invoked.
		/// </remarks>
		public static void TraceSuspendIf(this TraceSource source, Func<bool> predicate, Func<string> messageFactory)
		{
			Contract.Requires(source != null);
			Contract.Requires(predicate != null);
			Contract.Requires(messageFactory != null);

			var sourceSwitch = source.Switch;

			if (sourceSwitch.ShouldTrace(TraceEventType.Suspend) && predicate())
			{
				source.TraceEvent(TraceEventType.Suspend, eventId, messageFactory() ?? string.Empty);
			}
		}
#endif

		/// <summary>
		/// Sends the specified suspend message to all listeners if the specified <paramref name="predicate"/> is <see langword="true"/>.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="predicate">A value indicating whether the message is sent.</param>
		/// <param name="message">The message to be sent.</param>
		public static void TraceSuspendIf(this TraceSource source, bool predicate, string message)
		{
			Contract.Requires(source != null);

			if (predicate)
			{
				source.TraceEvent(TraceEventType.Suspend, eventId, message ?? string.Empty);
			}
		}

		/// <summary>
		/// Sends the specified suspend message to all listeners if the specified <paramref name="predicate"/> is <see langword="true"/>.
		/// </summary>
		/// <param name="source">The <see cref="TraceSource"/> object from which to send the message.</param>
		/// <param name="predicate">A value indicating whether the message is sent.</param>
		/// <param name="format">The message to be formatted.</param>
		/// <param name="args">The format arguments.</param>
		public static void TraceSuspendIf(this TraceSource source, bool predicate, string format, params object[] args)
		{
			Contract.Requires(source != null);

			if (predicate)
			{
				source.TraceEvent(TraceEventType.Suspend, eventId, format ?? string.Empty, args);
			}
		}
	}
}